Conversation
|
[CI]: Can one of the admins verify this patch? |
| const IGPUGraphicsPipeline* getBoundGraphicsPipeline() const { return m_boundGraphicsPipeline; } | ||
| const IGPUPipelineBase* getBoundGraphicsPipeline() const { return m_boundRasterizationPipeline; } |
There was a problem hiding this comment.
can we have a RasterizationPipelineBase, cause PipelineBase is also inherited from by RT and compute
| bool drawMeshTasks(const uint32_t groupCountX, const uint32_t groupCountY = 1, const uint32_t groupCountZ = 1); | ||
| inline bool drawMeshTasks(const hlsl::vector<uint16_t, 3> groupCount) { | ||
| return drawMeshTasks(groupCount.x, groupCount.y, groupCount.z); | ||
| } |
There was a problem hiding this comment.
I'd rather the hlsl::uint16_t3 be the primary signature, and the separate uint32 per dimension be the inline mapping to that
There was a problem hiding this comment.
can do a similar change to compute to match
| void CVulkanLogicalDevice::createGraphicsPipelines_impl( | ||
| IGPUPipelineCache* const pipelineCache, | ||
| const std::span<const IGPUGraphicsPipeline::SCreationParams> createInfos, | ||
| core::smart_refctd_ptr<IGPUGraphicsPipeline>* const output, | ||
| const SSpecializationValidationResult& validation | ||
| ) | ||
| { | ||
| auto getVkStencilOpStateFrom = [](const asset::SStencilOpParams& params)->VkStencilOpState | ||
| { | ||
| return { | ||
| .failOp = static_cast<VkStencilOp>(params.failOp), | ||
| .passOp = static_cast<VkStencilOp>(params.passOp), | ||
| .depthFailOp = static_cast<VkStencilOp>(params.depthFailOp), | ||
| .compareOp = static_cast<VkCompareOp>(params.compareOp) | ||
| }; | ||
| void PopulateViewport(VkPipelineViewportStateCreateInfo& outViewport, nbl::asset::SRasterizationParams const& raster) { | ||
| outViewport.viewportCount = raster.viewportCount; | ||
| // must be identical to viewport count unless VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT or VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT_EXT are used | ||
| outViewport.scissorCount = raster.viewportCount; | ||
| } | ||
|
|
||
|
|
||
| void PopulateRaster(VkPipelineRasterizationStateCreateInfo& outRaster, nbl::asset::SRasterizationParams const& raster) { | ||
| outRaster.depthClampEnable = raster.depthClampEnable; | ||
| outRaster.rasterizerDiscardEnable = raster.rasterizerDiscard; | ||
| outRaster.polygonMode = static_cast<VkPolygonMode>(raster.polygonMode); | ||
| outRaster.cullMode = static_cast<VkCullModeFlags>(raster.faceCullingMode); | ||
| outRaster.frontFace = raster.frontFaceIsCCW ? VK_FRONT_FACE_COUNTER_CLOCKWISE : VK_FRONT_FACE_CLOCKWISE; | ||
| outRaster.depthBiasEnable = raster.depthBiasEnable; | ||
| } | ||
|
|
||
| void PopulateMultisample(VkPipelineMultisampleStateCreateInfo& outMultisample, nbl::asset::SRasterizationParams const& raster) { | ||
| outMultisample.rasterizationSamples = static_cast<VkSampleCountFlagBits>(0x1 << raster.samplesLog2); | ||
| if (raster.minSampleShadingUnorm > 0) { | ||
| outMultisample.sampleShadingEnable = true; | ||
| outMultisample.minSampleShading = float(raster.minSampleShadingUnorm) / 255.f; | ||
| } | ||
| else { | ||
| outMultisample.sampleShadingEnable = false; | ||
| outMultisample.minSampleShading = 0.f; | ||
| } | ||
| outMultisample.pSampleMask = raster.sampleMask; | ||
| outMultisample.alphaToCoverageEnable = raster.alphaToCoverageEnable; | ||
| outMultisample.alphaToOneEnable = raster.alphaToOneEnable; | ||
| } | ||
| VkStencilOpState getVkStencilOpStateFrom(const asset::SStencilOpParams& params) { | ||
| return { | ||
| .failOp = static_cast<VkStencilOp>(params.failOp), | ||
| .passOp = static_cast<VkStencilOp>(params.passOp), | ||
| .depthFailOp = static_cast<VkStencilOp>(params.depthFailOp), | ||
| .compareOp = static_cast<VkCompareOp>(params.compareOp) | ||
| }; | ||
| } | ||
|
|
||
| const auto& features = getEnabledFeatures(); | ||
| void PopulateDepthStencil(VkPipelineDepthStencilStateCreateInfo& outDepthStencil, nbl::asset::SRasterizationParams const& raster) { | ||
| outDepthStencil.depthTestEnable = raster.depthTestEnable(); | ||
| outDepthStencil.depthWriteEnable = raster.depthWriteEnable; | ||
| outDepthStencil.depthCompareOp = static_cast<VkCompareOp>(raster.depthCompareOp); | ||
| outDepthStencil.depthBoundsTestEnable = raster.depthBoundsTestEnable; | ||
| outDepthStencil.stencilTestEnable = raster.stencilTestEnable(); | ||
| outDepthStencil.front = getVkStencilOpStateFrom(raster.frontStencilOps); | ||
| outDepthStencil.back = getVkStencilOpStateFrom(raster.backStencilOps); | ||
| } | ||
|
|
||
| void PopulateColorBlend( | ||
| VkPipelineColorBlendStateCreateInfo& outColorBlend, | ||
| VkPipelineColorBlendAttachmentState*& outColorBlendAttachmentState, | ||
| nbl::asset::SBlendParams const& blend, | ||
| nbl::asset::IRenderpass::SCreationParams::SSubpassDescription const& subpass | ||
| ) { | ||
| //outColorBlend->flags no attachment order access yet | ||
| outColorBlend.logicOpEnable = blend.logicOp != asset::ELO_NO_OP; | ||
| outColorBlend.logicOp = getVkLogicOpFromLogicOp(blend.logicOp); | ||
| outColorBlend.pAttachments = outColorBlendAttachmentState; | ||
| for (auto i = 0; i < IGPURenderpass::SCreationParams::SSubpassDescription::MaxColorAttachments; i++) { | ||
| if (subpass.colorAttachments[i].render.used()) { | ||
| const auto& params = blend.blendParams[i]; | ||
| outColorBlendAttachmentState->blendEnable = params.blendEnabled(); | ||
| outColorBlendAttachmentState->srcColorBlendFactor = getVkBlendFactorFromBlendFactor(static_cast<asset::E_BLEND_FACTOR>(params.srcColorFactor)); | ||
| outColorBlendAttachmentState->dstColorBlendFactor = getVkBlendFactorFromBlendFactor(static_cast<asset::E_BLEND_FACTOR>(params.dstColorFactor)); | ||
| outColorBlendAttachmentState->colorBlendOp = getVkBlendOpFromBlendOp(static_cast<asset::E_BLEND_OP>(params.colorBlendOp)); | ||
| outColorBlendAttachmentState->srcAlphaBlendFactor = getVkBlendFactorFromBlendFactor(static_cast<asset::E_BLEND_FACTOR>(params.srcAlphaFactor)); | ||
| outColorBlendAttachmentState->dstAlphaBlendFactor = getVkBlendFactorFromBlendFactor(static_cast<asset::E_BLEND_FACTOR>(params.dstAlphaFactor)); | ||
| outColorBlendAttachmentState->alphaBlendOp = getVkBlendOpFromBlendOp(static_cast<asset::E_BLEND_OP>(params.alphaBlendOp)); | ||
| outColorBlendAttachmentState->colorWriteMask = getVkColorComponentFlagsFromColorWriteMask(params.colorWriteMask); | ||
| outColorBlendAttachmentState++; | ||
| //^that pointer iterator is how we ensure the attachments or consecutive | ||
| } | ||
| } | ||
| outColorBlend.attachmentCount = std::distance<const VkPipelineColorBlendAttachmentState*>(outColorBlend.pAttachments, outColorBlendAttachmentState); | ||
| } | ||
|
|
||
| template<typename SCreationParams> | ||
| void PopulateMeshGraphicsCommonData( | ||
| const std::span<const SCreationParams> createInfos, | ||
| core::vector<VkGraphicsPipelineCreateInfo>& vk_createInfos, | ||
|
|
||
| core::vector<VkPipelineViewportStateCreateInfo>& vk_viewportStates, | ||
| core::vector<VkPipelineRasterizationStateCreateInfo>& vk_rasterizationStates, | ||
| core::vector<VkPipelineMultisampleStateCreateInfo>& vk_multisampleStates, | ||
| core::vector<VkPipelineDepthStencilStateCreateInfo>& vk_depthStencilStates, | ||
| core::vector<VkPipelineColorBlendStateCreateInfo>& vk_colorBlendStates, | ||
| core::vector<VkPipelineColorBlendAttachmentState>& vk_colorBlendAttachmentStates, | ||
|
|
||
| core::vector<VkDynamicState>& vk_dynamicStates, | ||
| const VkPipelineDynamicStateCreateInfo& vk_dynamicStateCreateInfo | ||
| ) { | ||
| //the main concern is lifetime, so don't want to construct, move, or copy anything in here | ||
|
|
||
| auto outColorBlendAttachmentState = vk_colorBlendAttachmentStates.data(); //the pointer iterator is used | ||
|
|
||
| core::vector<VkDynamicState> vk_dynamicStates = { | ||
|
|
||
| for (uint32_t i = 0; i < createInfos.size(); i++) { //whats the maximum number of pipelines that can be created at once? uint32_t to be safe | ||
| auto& info = createInfos[i]; | ||
| const auto& blend = info.cached.blend; | ||
| const auto& raster = info.cached.rasterization; | ||
| const auto& subpass = info.renderpass->getCreationParameters().subpasses[info.cached.subpassIx]; | ||
|
|
||
| initPipelineCreateInfo(&vk_createInfos[i], info); | ||
|
|
||
| PopulateViewport(vk_viewportStates[i], raster); | ||
| PopulateRaster(vk_rasterizationStates[i], raster); | ||
| PopulateMultisample(vk_multisampleStates[i], raster); | ||
| PopulateDepthStencil(vk_depthStencilStates[i], raster); | ||
| PopulateColorBlend(vk_colorBlendStates[i], outColorBlendAttachmentState, blend, subpass); | ||
| //PopulateDynamicState(dynState, ?) | ||
|
|
||
|
|
||
| vk_createInfos[i].pViewportState = &vk_viewportStates[i]; | ||
| vk_createInfos[i].pRasterizationState = &vk_rasterizationStates[i]; | ||
| vk_createInfos[i].pMultisampleState = &vk_multisampleStates[i]; | ||
| vk_createInfos[i].pDepthStencilState = &vk_depthStencilStates[i]; | ||
| vk_createInfos[i].pColorBlendState = &vk_colorBlendStates[i]; | ||
| vk_createInfos[i].pDynamicState = &vk_dynamicStateCreateInfo; | ||
| vk_createInfos[i].renderPass = static_cast<const CVulkanRenderpass*>(info.renderpass)->getInternalObject(); | ||
| vk_createInfos[i].subpass = info.cached.subpassIx; | ||
| //handle | ||
| //index | ||
| //layout? | ||
| // ^ handled in initPipelineCreateInfo | ||
| } | ||
| } | ||
|
|
||
| core::vector<VkDynamicState> getDefaultDynamicStates(SPhysicalDeviceFeatures const& features) { | ||
| core::vector<VkDynamicState> ret = { |
There was a problem hiding this comment.
@kevyuu you review this and give it the okay
There was a problem hiding this comment.
actually wait a ssecond, @GDBobby I think you could turn all these free floating functions into struct methods of a struct that has reference members like core::vector<>& or span members const std::span<> since the vectors are preallocated
| //maximum cleanliness,i tried it and im not a big fan | ||
| //struct CommonPipelineStruct { | ||
| // VkPipelineRasterizationStateCreateInfo vk_rasterizationStates{ VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,nullptr,0 }; | ||
| // VkPipelineMultisampleStateCreateInfo vk_multisampleStates{ VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,nullptr,0 }; | ||
| // VkPipelineDepthStencilStateCreateInfo vk_depthStencilStates{ VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,nullptr,0 }; | ||
| // VkPipelineColorBlendStateCreateInfo vk_colorBlendStates{ VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,nullptr,0 }; | ||
| // core::vector<VkPipelineColorBlendAttachmentState> vk_colorBlendAttachmentStates{ IGPURenderpass::SCreationParams::SSubpassDescription::MaxColorAttachments }; | ||
| //}; |
There was a problem hiding this comment.
me neither because this messes with our SVO later on
| core::vector<VkPipelineViewportStateCreateInfo>& vk_viewportStates, | ||
| core::vector<VkPipelineRasterizationStateCreateInfo>& vk_rasterizationStates, | ||
| core::vector<VkPipelineMultisampleStateCreateInfo>& vk_multisampleStates, | ||
| core::vector<VkPipelineDepthStencilStateCreateInfo>& vk_depthStencilStates, | ||
| core::vector<VkPipelineColorBlendStateCreateInfo>& vk_colorBlendStates, | ||
| core::vector<VkPipelineColorBlendAttachmentState>& vk_colorBlendAttachmentStates, | ||
|
|
||
| core::vector<VkDynamicState>& vk_dynamicStates, | ||
| const VkPipelineDynamicStateCreateInfo& vk_dynamicStateCreateInfo |
There was a problem hiding this comment.
you can create a struct with reference members though to pack this all up
| //not used in mesh pipelines | ||
| for (auto& outCreateInfo : vk_createInfos) { | ||
| outCreateInfo.pVertexInputState = nullptr; | ||
| outCreateInfo.pInputAssemblyState = nullptr; | ||
| outCreateInfo.pTessellationState = nullptr; | ||
| } |
There was a problem hiding this comment.
because we give a default value to the vector constructor of vk_createInfos, these should be nullptr initialized already unless you write to them with your utility functions
| //maximum cleanliness, I create a struct that holds this for mesh and graphics? | ||
| core::vector<VkGraphicsPipelineCreateInfo> vk_createInfos(createInfos.size(), { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,nullptr }); | ||
|
|
||
| core::vector<VkPipelineRasterizationStateCreateInfo> vk_rasterizationStates(createInfos.size(), { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,nullptr,0 }); | ||
| core::vector<VkPipelineMultisampleStateCreateInfo> vk_multisampleStates(createInfos.size(), { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,nullptr,0 }); | ||
| core::vector<VkPipelineDepthStencilStateCreateInfo> vk_depthStencilStates(createInfos.size(), { VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,nullptr,0 }); | ||
| core::vector<VkPipelineColorBlendStateCreateInfo> vk_colorBlendStates(createInfos.size(), { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,nullptr,0 }); | ||
| core::vector<VkPipelineColorBlendAttachmentState> vk_colorBlendAttachmentStates(createInfos.size() * IGPURenderpass::SCreationParams::SSubpassDescription::MaxColorAttachments); | ||
|
|
||
| core::vector<VkDynamicState> vk_dynamicStates = getDefaultDynamicStates(features); |
There was a problem hiding this comment.
you can but keep it separate from the util struct that works on spans
| core::vector<VkGraphicsPipelineCreateInfo> vk_createInfos(createInfos.size(),{VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,nullptr}); | ||
|
|
||
| const auto maxShaderStages = createInfos.size()*IGPUGraphicsPipeline::GRAPHICS_SHADER_STAGE_COUNT; | ||
| core::vector<VkPipelineShaderStageCreateInfo> vk_shaderStage(maxShaderStages,{VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,nullptr}); | ||
| core::vector<VkShaderModuleCreateInfo> vk_shaderModule(maxShaderStages,{VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,nullptr, 0}); | ||
| core::vector<std::string> entryPoints(maxShaderStages); | ||
| core::vector<VkPipelineShaderStageRequiredSubgroupSizeCreateInfo> vk_requiredSubgroupSize(maxShaderStages,{ | ||
| VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO,nullptr | ||
| }); | ||
| core::vector<VkSpecializationInfo> vk_specializationInfos(maxShaderStages,{0,nullptr,0,nullptr}); | ||
| core::vector<VkSpecializationMapEntry> vk_specializationMapEntry(validation.count); | ||
| core::vector<uint8_t> specializationData(validation.dataSize); | ||
| core::vector<VkPipelineVertexInputStateCreateInfo> vk_vertexInput(createInfos.size(),{VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,nullptr,0}); | ||
| core::vector<VkVertexInputBindingDescription> vk_inputBinding(createInfos.size()*asset::SVertexInputParams::MAX_ATTR_BUF_BINDING_COUNT); | ||
| core::vector<VkVertexInputAttributeDescription> vk_inputAttribute(createInfos.size()*asset::SVertexInputParams::MAX_VERTEX_ATTRIB_COUNT); | ||
| core::vector<VkPipelineInputAssemblyStateCreateInfo> vk_inputAssembly(createInfos.size(),{VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,nullptr,0}); | ||
| core::vector<VkPipelineTessellationStateCreateInfo> vk_tessellation(createInfos.size(),{VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO,nullptr,0}); | ||
| core::vector<VkPipelineViewportStateCreateInfo> vk_viewportStates(createInfos.size(),{ | ||
| //maximum cleanliness, I create a struct that holds this for mesh and graphics? | ||
| core::vector<VkGraphicsPipelineCreateInfo> vk_createInfos(createInfos.size(), { VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO,nullptr }); | ||
|
|
||
| core::vector<VkPipelineRasterizationStateCreateInfo> vk_rasterizationStates(createInfos.size(), { VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,nullptr,0 }); | ||
| core::vector<VkPipelineMultisampleStateCreateInfo> vk_multisampleStates(createInfos.size(), { VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,nullptr,0 }); | ||
| core::vector<VkPipelineDepthStencilStateCreateInfo> vk_depthStencilStates(createInfos.size(), { VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,nullptr,0 }); | ||
| core::vector<VkPipelineColorBlendStateCreateInfo> vk_colorBlendStates(createInfos.size(), { VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,nullptr,0 }); | ||
| core::vector<VkPipelineColorBlendAttachmentState> vk_colorBlendAttachmentStates(createInfos.size() * IGPURenderpass::SCreationParams::SSubpassDescription::MaxColorAttachments); | ||
|
|
||
| core::vector<VkDynamicState> vk_dynamicStates = getDefaultDynamicStates(features); | ||
|
|
||
| const VkPipelineDynamicStateCreateInfo vk_dynamicStateCreateInfo = { | ||
| .sType = VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO, | ||
| .pNext = nullptr, | ||
| .flags = 0u, | ||
| .dynamicStateCount = static_cast<uint32_t>(vk_dynamicStates.size()), | ||
| .pDynamicStates = vk_dynamicStates.data() | ||
| }; | ||
| core::vector<VkPipelineViewportStateCreateInfo> vk_viewportStates(createInfos.size(), { | ||
| .sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO, | ||
| .pNext = nullptr, // the extensions that interest us have a dynamic state variant anyway | ||
| .flags = 0, // must be 0 | ||
| .viewportCount = 0, | ||
| .pViewports = nullptr, | ||
| .scissorCount = 0, | ||
| .pScissors = nullptr, | ||
| }); | ||
| core::vector<VkPipelineRasterizationStateCreateInfo> vk_rasterizationStates(createInfos.size(),{VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO,nullptr,0}); | ||
| core::vector<VkPipelineMultisampleStateCreateInfo> vk_multisampleStates(createInfos.size(),{VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO,nullptr,0}); | ||
| core::vector<VkPipelineDepthStencilStateCreateInfo> vk_depthStencilStates(createInfos.size(),{VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO,nullptr,0}); | ||
| core::vector<VkPipelineColorBlendStateCreateInfo> vk_colorBlendStates(createInfos.size(),{VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO,nullptr,0}); | ||
| core::vector<VkPipelineColorBlendAttachmentState> vk_colorBlendAttachmentStates(createInfos.size()*IGPURenderpass::SCreationParams::SSubpassDescription::MaxColorAttachments); | ||
| }); | ||
|
|
||
| PopulateMeshGraphicsCommonData( | ||
| createInfos, vk_createInfos, | ||
|
|
||
| vk_viewportStates, | ||
| vk_rasterizationStates, | ||
| vk_multisampleStates, | ||
| vk_depthStencilStates, | ||
| vk_colorBlendStates, | ||
| vk_colorBlendAttachmentStates, | ||
|
|
||
| vk_dynamicStates, vk_dynamicStateCreateInfo | ||
| ); | ||
|
|
||
|
|
||
| core::vector<VkVertexInputBindingDescription> vk_inputBinding(createInfos.size() * asset::SVertexInputParams::MAX_ATTR_BUF_BINDING_COUNT); | ||
| core::vector<VkVertexInputAttributeDescription> vk_inputAttribute(createInfos.size() * asset::SVertexInputParams::MAX_VERTEX_ATTRIB_COUNT); | ||
| core::vector<VkPipelineInputAssemblyStateCreateInfo> vk_inputAssembly(createInfos.size(), { VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO,nullptr,0 }); | ||
| core::vector<VkPipelineTessellationStateCreateInfo> vk_tessellation(createInfos.size(), { VK_STRUCTURE_TYPE_PIPELINE_TESSELLATION_STATE_CREATE_INFO,nullptr,0 }); | ||
| core::vector<VkPipelineVertexInputStateCreateInfo> vk_vertexInput(createInfos.size(), { VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO,nullptr,0 }); | ||
|
|
||
| auto outCreateInfo = vk_createInfos.data(); | ||
| auto outShaderStage = vk_shaderStage.data(); | ||
| auto outEntryPoints = entryPoints.data(); | ||
| auto outShaderModule = vk_shaderModule.data(); | ||
| auto outRequiredSubgroupSize = vk_requiredSubgroupSize.data(); | ||
| auto outSpecInfo = vk_specializationInfos.data(); | ||
| auto outSpecMapEntry = vk_specializationMapEntry.data(); | ||
| auto outSpecData = specializationData.data(); | ||
| auto outVertexInput = vk_vertexInput.data(); | ||
| auto outInputBinding = vk_inputBinding.data(); | ||
| auto outInputAttribute = vk_inputAttribute.data(); | ||
| auto outInputAssembly = vk_inputAssembly.data(); | ||
| auto outTessellation = vk_tessellation.data(); | ||
| auto outViewport = vk_viewportStates.data(); | ||
| auto outRaster = vk_rasterizationStates.data(); | ||
| auto outMultisample = vk_multisampleStates.data(); | ||
| auto outDepthStencil = vk_depthStencilStates.data(); | ||
| auto outColorBlend = vk_colorBlendStates.data(); | ||
| auto outColorBlendAttachmentState = vk_colorBlendAttachmentStates.data(); | ||
| auto outInputAssembly = vk_inputAssembly.data(); | ||
|
|
||
| //ill acknowledge this additional looping is a little ugly | ||
| //input and tess | ||
| for (const auto& info : createInfos) | ||
| { | ||
| initPipelineCreateInfo(outCreateInfo,info); | ||
| outCreateInfo->pStages = outShaderStage; | ||
| auto processSpecShader = [&](IGPUPipelineBase::SShaderSpecInfo spec, hlsl::ShaderStage shaderStage) | ||
| { | ||
| if (spec.shader) | ||
| { | ||
| *(outShaderStage++) = getVkShaderStageCreateInfoFrom(spec, shaderStage, false, outShaderModule, outEntryPoints, outRequiredSubgroupSize, outSpecInfo, outSpecMapEntry, outSpecData); | ||
| outCreateInfo->stageCount = std::distance<decltype(outCreateInfo->pStages)>(outCreateInfo->pStages, outShaderStage); | ||
| } | ||
| }; | ||
| processSpecShader(info.vertexShader, hlsl::ShaderStage::ESS_VERTEX); | ||
| processSpecShader(info.tesselationControlShader, hlsl::ShaderStage::ESS_TESSELLATION_CONTROL); | ||
| processSpecShader(info.tesselationEvaluationShader, hlsl::ShaderStage::ESS_TESSELLATION_EVALUATION); | ||
| processSpecShader(info.geometryShader, hlsl::ShaderStage::ESS_GEOMETRY); | ||
| processSpecShader(info.fragmentShader, hlsl::ShaderStage::ESS_FRAGMENT); | ||
|
|
||
| // when dealing with mesh shaders, the vertex input and assembly state will be null | ||
| { | ||
| { | ||
| const auto& vertexInputParams = info.cached.vertexInput; | ||
| outVertexInput->pVertexBindingDescriptions = outInputBinding; | ||
| for (auto b=0u; b<asset::SVertexInputParams::MAX_ATTR_BUF_BINDING_COUNT; b++) | ||
| if (vertexInputParams.enabledBindingFlags&(1<<b)) | ||
| const auto& vertexInputParams = info.cached.vertexInput; | ||
| outVertexInput->pVertexBindingDescriptions = outInputBinding; | ||
| for (auto b = 0u; b < asset::SVertexInputParams::MAX_ATTR_BUF_BINDING_COUNT; b++) | ||
| if (vertexInputParams.enabledBindingFlags & (1 << b)) | ||
| { | ||
| outInputBinding->binding = b; | ||
| outInputBinding->stride = vertexInputParams.bindings[b].stride; | ||
| outInputBinding->inputRate = static_cast<VkVertexInputRate>(vertexInputParams.bindings[b].inputRate); | ||
| outInputBinding++; | ||
| } | ||
| outVertexInput->vertexBindingDescriptionCount = std::distance<const VkVertexInputBindingDescription*>(outVertexInput->pVertexBindingDescriptions,outInputBinding); | ||
| outVertexInput->pVertexAttributeDescriptions = outInputAttribute; | ||
| for (auto l=0u; l<asset::SVertexInputParams::MAX_VERTEX_ATTRIB_COUNT; l++) | ||
| if (vertexInputParams.enabledAttribFlags&(1<<l)) | ||
| outVertexInput->vertexBindingDescriptionCount = std::distance<const VkVertexInputBindingDescription*>(outVertexInput->pVertexBindingDescriptions, outInputBinding); | ||
| outVertexInput->pVertexAttributeDescriptions = outInputAttribute; | ||
| for (auto l = 0u; l < asset::SVertexInputParams::MAX_VERTEX_ATTRIB_COUNT; l++) | ||
| if (vertexInputParams.enabledAttribFlags & (1 << l)) | ||
| { | ||
| outInputAttribute->location = l; | ||
| outInputAttribute->binding = vertexInputParams.attributes[l].binding; | ||
| outInputAttribute->format = getVkFormatFromFormat(static_cast<asset::E_FORMAT>(vertexInputParams.attributes[l].format)); | ||
| outInputAttribute->offset = vertexInputParams.attributes[l].relativeOffset; | ||
| outInputAttribute++; | ||
| } | ||
| outVertexInput->vertexAttributeDescriptionCount = std::distance<const VkVertexInputAttributeDescription*>(outVertexInput->pVertexAttributeDescriptions,outInputAttribute); | ||
| } | ||
| outCreateInfo->pVertexInputState = outVertexInput++; | ||
| { | ||
| const auto& primAssParams = info.cached.primitiveAssembly; | ||
| outInputAssembly->topology = static_cast<VkPrimitiveTopology>(primAssParams.primitiveType); | ||
| outInputAssembly->primitiveRestartEnable = primAssParams.primitiveRestartEnable; | ||
| } | ||
| outCreateInfo->pInputAssemblyState = outInputAssembly++; | ||
| outVertexInput->vertexAttributeDescriptionCount = std::distance<const VkVertexInputAttributeDescription*>(outVertexInput->pVertexAttributeDescriptions, outInputAttribute); | ||
| } | ||
| outCreateInfo->pVertexInputState = outVertexInput++; | ||
| { | ||
| const auto& primAssParams = info.cached.primitiveAssembly; | ||
| outInputAssembly->topology = static_cast<VkPrimitiveTopology>(primAssParams.primitiveType); | ||
| outInputAssembly->primitiveRestartEnable = primAssParams.primitiveRestartEnable; | ||
| } | ||
| outCreateInfo->pInputAssemblyState = outInputAssembly++; | ||
|
|
||
| if (info.tesselationControlShader.shader || info.tesselationEvaluationShader.shader) | ||
| { | ||
| outTessellation->patchControlPoints = info.cached.primitiveAssembly.tessPatchVertCount; | ||
| outCreateInfo->pTessellationState = outTessellation++; | ||
| } | ||
|
|
||
| const auto& raster = info.cached.rasterization; | ||
| { | ||
| outViewport->viewportCount = raster.viewportCount; | ||
| // must be identical to viewport count unless VK_DYNAMIC_STATE_VIEWPORT_WITH_COUNT_EXT or VK_DYNAMIC_STATE_SCISSOR_WITH_COUNT_EXT are used | ||
| outViewport->scissorCount = raster.viewportCount; | ||
| outCreateInfo->pViewportState = outViewport++; | ||
| } | ||
| { | ||
| outRaster->depthClampEnable = raster.depthClampEnable; | ||
| outRaster->rasterizerDiscardEnable = raster.rasterizerDiscard; | ||
| outRaster->polygonMode = static_cast<VkPolygonMode>(raster.polygonMode); | ||
| outRaster->cullMode = static_cast<VkCullModeFlags>(raster.faceCullingMode); | ||
| outRaster->frontFace = raster.frontFaceIsCCW ? VK_FRONT_FACE_COUNTER_CLOCKWISE:VK_FRONT_FACE_CLOCKWISE; | ||
| outRaster->depthBiasEnable = raster.depthBiasEnable; | ||
| outCreateInfo->pRasterizationState = outRaster++; | ||
| } | ||
| { | ||
| outMultisample->rasterizationSamples = static_cast<VkSampleCountFlagBits>(0x1<<raster.samplesLog2); | ||
| if (raster.minSampleShadingUnorm>0) | ||
| { | ||
| outMultisample->sampleShadingEnable = true; | ||
| outMultisample->minSampleShading = float(raster.minSampleShadingUnorm)/255.f; | ||
| } | ||
| else | ||
| { | ||
| outMultisample->sampleShadingEnable = false; | ||
| outMultisample->minSampleShading = 0.f; | ||
| } | ||
| outMultisample->pSampleMask = raster.sampleMask; | ||
| outMultisample->alphaToCoverageEnable = raster.alphaToCoverageEnable; | ||
| outMultisample->alphaToOneEnable = raster.alphaToOneEnable; | ||
| outCreateInfo->pMultisampleState = outMultisample++; | ||
| } | ||
| { | ||
| //outDepthStencil->flags no attachment order access yet | ||
| outDepthStencil->depthTestEnable = raster.depthTestEnable(); | ||
| outDepthStencil->depthWriteEnable = raster.depthWriteEnable; | ||
| outDepthStencil->depthCompareOp = static_cast<VkCompareOp>(raster.depthCompareOp); | ||
| outDepthStencil->depthBoundsTestEnable = raster.depthBoundsTestEnable; | ||
| outDepthStencil->stencilTestEnable = raster.stencilTestEnable(); | ||
| outDepthStencil->front = getVkStencilOpStateFrom(raster.frontStencilOps); | ||
| outDepthStencil->back = getVkStencilOpStateFrom(raster.backStencilOps); | ||
| outCreateInfo->pDepthStencilState = outDepthStencil++; | ||
| } | ||
| { | ||
| const auto& blend = info.cached.blend; | ||
| const auto& subpass = info.renderpass->getCreationParameters().subpasses[info.cached.subpassIx]; | ||
| //outColorBlend->flags no attachment order access yet | ||
| outColorBlend->logicOpEnable = blend.logicOp!=asset::ELO_NO_OP; | ||
| outColorBlend->logicOp = getVkLogicOpFromLogicOp(blend.logicOp); | ||
| outColorBlend->pAttachments = outColorBlendAttachmentState; | ||
| for (auto i=0; i<IGPURenderpass::SCreationParams::SSubpassDescription::MaxColorAttachments; i++) | ||
| if (subpass.colorAttachments[i].render.used()) | ||
| outCreateInfo++; | ||
| } | ||
|
|
||
| const auto maxShaderStages = createInfos.size() * IGPUGraphicsPipeline::GRAPHICS_SHADER_STAGE_COUNT; | ||
| core::vector<VkPipelineShaderStageCreateInfo> vk_shaderStage(maxShaderStages, { VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO,nullptr }); | ||
| core::vector<VkShaderModuleCreateInfo> vk_shaderModule(maxShaderStages, { VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO,nullptr, 0 }); | ||
| core::vector<std::string> entryPoints(maxShaderStages); | ||
| core::vector<VkPipelineShaderStageRequiredSubgroupSizeCreateInfo> vk_requiredSubgroupSize(maxShaderStages, { | ||
| VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_REQUIRED_SUBGROUP_SIZE_CREATE_INFO,nullptr | ||
| }); | ||
| core::vector<VkSpecializationInfo> vk_specializationInfos(maxShaderStages, { 0,nullptr,0,nullptr }); | ||
| core::vector<VkSpecializationMapEntry> vk_specializationMapEntry(validation.count); | ||
| core::vector<uint8_t> specializationData(validation.dataSize); | ||
|
|
||
| outCreateInfo = vk_createInfos.data(); | ||
| auto outShaderStage = vk_shaderStage.data(); | ||
| auto outEntryPoints = entryPoints.data(); | ||
| auto outShaderModule = vk_shaderModule.data(); | ||
| auto outRequiredSubgroupSize = vk_requiredSubgroupSize.data(); | ||
| auto outSpecInfo = vk_specializationInfos.data(); | ||
| auto outSpecMapEntry = vk_specializationMapEntry.data(); | ||
| auto outSpecData = specializationData.data(); | ||
|
|
||
| //shader | ||
| for (const auto& info : createInfos) | ||
| { | ||
| outCreateInfo->pStages = outShaderStage; | ||
| auto processSpecShader = [&](IGPUPipelineBase::SShaderSpecInfo spec, hlsl::ShaderStage shaderStage) | ||
| { | ||
| const auto& params = blend.blendParams[i]; | ||
| outColorBlendAttachmentState->blendEnable = params.blendEnabled(); | ||
| outColorBlendAttachmentState->srcColorBlendFactor = getVkBlendFactorFromBlendFactor(static_cast<asset::E_BLEND_FACTOR>(params.srcColorFactor)); | ||
| outColorBlendAttachmentState->dstColorBlendFactor = getVkBlendFactorFromBlendFactor(static_cast<asset::E_BLEND_FACTOR>(params.dstColorFactor)); | ||
| outColorBlendAttachmentState->colorBlendOp = getVkBlendOpFromBlendOp(static_cast<asset::E_BLEND_OP>(params.colorBlendOp)); | ||
| outColorBlendAttachmentState->srcAlphaBlendFactor = getVkBlendFactorFromBlendFactor(static_cast<asset::E_BLEND_FACTOR>(params.srcAlphaFactor)); | ||
| outColorBlendAttachmentState->dstAlphaBlendFactor = getVkBlendFactorFromBlendFactor(static_cast<asset::E_BLEND_FACTOR>(params.dstAlphaFactor)); | ||
| outColorBlendAttachmentState->alphaBlendOp = getVkBlendOpFromBlendOp(static_cast<asset::E_BLEND_OP>(params.alphaBlendOp)); | ||
| outColorBlendAttachmentState->colorWriteMask = getVkColorComponentFlagsFromColorWriteMask(params.colorWriteMask); | ||
| outColorBlendAttachmentState++; | ||
| } | ||
| outColorBlend->attachmentCount = std::distance<const VkPipelineColorBlendAttachmentState*>(outColorBlend->pAttachments,outColorBlendAttachmentState); | ||
| outCreateInfo->pColorBlendState = outColorBlend++; | ||
| } | ||
| outCreateInfo->pDynamicState = &vk_dynamicStateCreateInfo; | ||
| outCreateInfo->renderPass = static_cast<const CVulkanRenderpass*>(info.renderpass)->getInternalObject(); | ||
| outCreateInfo->subpass = info.cached.subpassIx; | ||
| if (spec.shader) | ||
| { | ||
| *(outShaderStage++) = getVkShaderStageCreateInfoFrom(spec, | ||
| shaderStage, | ||
| false, | ||
| outShaderModule, | ||
| outEntryPoints, | ||
| outRequiredSubgroupSize, | ||
| outSpecInfo, | ||
| outSpecMapEntry, | ||
| outSpecData | ||
| ); | ||
| outCreateInfo->stageCount = std::distance<decltype(outCreateInfo->pStages)>(outCreateInfo->pStages, outShaderStage); | ||
| } | ||
| }; | ||
| processSpecShader(info.vertexShader, hlsl::ShaderStage::ESS_VERTEX); | ||
| processSpecShader(info.tesselationControlShader, hlsl::ShaderStage::ESS_TESSELLATION_CONTROL); | ||
| processSpecShader(info.tesselationEvaluationShader, hlsl::ShaderStage::ESS_TESSELLATION_EVALUATION); | ||
| processSpecShader(info.geometryShader, hlsl::ShaderStage::ESS_GEOMETRY); | ||
| processSpecShader(info.fragmentShader, hlsl::ShaderStage::ESS_FRAGMENT); | ||
|
|
||
| outCreateInfo++; | ||
| } | ||
|
|
There was a problem hiding this comment.
@kevyuu review this
| { | ||
|
|
||
| CVulkanMeshPipeline::~CVulkanMeshPipeline() | ||
| { |
There was a problem hiding this comment.
dont do extra indents in namespaces
| //potentially collapse this so Mesh just uses CVulkanGraphicsPipeline | ||
| //if thats done, BindMesh can go away | ||
| class CVulkanMeshPipeline final : public IGPUMeshPipeline |
There was a problem hiding this comment.
you still need correct inheritance unfortunately, you could template the class though
template<typename Base> requires std::is_base_of_v<IGPURasterizationPipeline,Base>
class CVulkanRasterizationPipeline : public Base| meshShaderFeatures.primitiveFragmentShadingRateMeshShader = VK_FALSE;//needs to be explicitly set? | ||
| meshShaderFeatures.meshShaderQueries = VK_FALSE; | ||
| meshShaderFeatures.multiviewMeshShader = VK_FALSE; |
There was a problem hiding this comment.
the question is, for regular Multiview, queries and Shading rate, do we currently have them as limits or features?
| //check if features are existant first | ||
| //potentially put a copy of VkPhysicalDeviceMeshShaderFeaturesEXT directly into features | ||
| //depends on the less obvious properties | ||
| if (isExtensionSupported(VK_EXT_MESH_SHADER_EXTENSION_NAME)) { | ||
| features.meshShader = meshShaderFeatures.meshShader; | ||
| features.taskShader = meshShaderFeatures.taskShader; | ||
| //TODO | ||
| //VkBool32 multiviewMeshShader; | ||
| //VkBool32 primitiveFragmentShadingRateMeshShader; | ||
| //VkBool32 meshShaderQueries; | ||
|
|
||
| //VkPhysicalDeviceMeshShaderPropertiesEXT | ||
| //#define LIMIT_INIT_MESH(limitMemberName) properties.limits.limitMemberName = meshShaderProperties.limitMemberName | ||
| //LIMIT_INIT_MESH(maxTaskWorkGroupTotalCount); | ||
| //LIMIT_INIT_MESH(maxTaskWorkGroupInvocations); | ||
| //LIMIT_INIT_MESH(maxTaskPayloadSize); | ||
| //LIMIT_INIT_MESH(maxTaskSharedMemorySize); | ||
| //LIMIT_INIT_MESH(maxTaskPayloadAndSharedMemorySize); | ||
| //LIMIT_INIT_MESH(maxMeshWorkGroupInvocations); | ||
| //LIMIT_INIT_MESH(maxMeshSharedMemorySize); | ||
| //LIMIT_INIT_MESH(maxMeshPayloadAndSharedMemorySize); | ||
| //LIMIT_INIT_MESH(maxMeshOutputMemorySize); | ||
| //LIMIT_INIT_MESH(maxMeshOutputComponents); | ||
| //LIMIT_INIT_MESH(maxMeshOutputVertices); | ||
| //LIMIT_INIT_MESH(maxMeshOutputPrimitives); | ||
| //LIMIT_INIT_MESH(maxMeshOutputLayers); | ||
| //LIMIT_INIT_MESH(maxMeshMultiviewViewCount); | ||
| //LIMIT_INIT_MESH(maxMeshOutputPerVertexGranularity); | ||
| //LIMIT_INIT_MESH(maxMeshOutputPerPrimitiveGranularity); | ||
|
|
||
| //for(uint8_t i = 0; i < 3; i++){ | ||
| // LIMIT_INIT_MESH(maxTaskWorkGroupCount[i]); | ||
| // LIMIT_INIT_MESH(maxTaskWorkGroupSize[i]); | ||
| // LIMIT_INIT_MESH(maxMeshWorkGroupCount[i]); | ||
| // LIMIT_INIT_MESH(maxMeshWorkGroupSize[i]); | ||
| //} | ||
| //#undef LIMIT_INIT_MESH | ||
| } |
There was a problem hiding this comment.
@Erfan-Ahmadi review and advise on how to expose
| return drawMeshTasks_impl(groupCountX, groupCountY, groupCountZ); | ||
| } | ||
|
|
||
| bool IGPUCommandBuffer::drawMeshTasksIndirect(const asset::SBufferBinding<const IGPUBuffer>& binding, const uint32_t drawCount, uint32_t stride) |
There was a problem hiding this comment.
btw is there a flavour of task shaders where count comes from a buffer, like Multi Draw Indirect ?
| } | ||
| if (invalidBufferRange({ binding.offset,stride * (drawCount - 1u) + sizeof(hlsl::DrawMeshTasksIndirectCommand_t),binding.buffer }, alignof(uint32_t), IGPUBuffer::EUF_INDIRECT_BUFFER_BIT)) | ||
| return false; | ||
| } // i get the feeling the vk command shouldnt be called if drawCount is 0, but this is how drawindirect does it |
There was a problem hiding this comment.
check the spec and decide
| inline std::span<SShaderSpecInfo> getSpecInfos(const hlsl::ShaderStage stage) | ||
| { | ||
| return base_t::getSpecInfos(stage); | ||
| } |
There was a problem hiding this comment.
you can't hand out mutable spans without checking immutability first
| SShaderSpecInfo* getSpecInfo(const hlsl::ShaderStage stage) | ||
| { | ||
| if (!isMutable()) return nullptr; | ||
| switch (stage) { | ||
| case hlsl::ShaderStage::ESS_TASK: return &m_specInfos[0]; | ||
| case hlsl::ShaderStage::ESS_MESH: return &m_specInfos[1]; | ||
| case hlsl::ShaderStage::ESS_FRAGMENT: return &m_specInfos[2]; | ||
| } | ||
| return nullptr; | ||
| } | ||
|
|
||
| const SShaderSpecInfo* getSpecInfo(const hlsl::ShaderStage stage) const | ||
| { | ||
| const auto stageIndex = stageToIndex(stage); | ||
| if (stageIndex != -1) | ||
| return &m_specInfos[stageIndex]; | ||
| return nullptr; | ||
| } |
There was a problem hiding this comment.
why do we have duplicate code, the single pointer return value signatures should go in ICPURasterizationPipeline (these are pipelines which can only have one shader per stage
There was a problem hiding this comment.
also should probably be done in terms of span<> getSpecInfo(stage)
| inline const SCachedCreationParams& getCachedCreationParams() const | ||
| { | ||
| return pipeline_base_t::getCachedCreationParams(); | ||
| } | ||
|
|
||
| inline SCachedCreationParams& getCachedCreationParams() | ||
| { | ||
| assert(isMutable()); | ||
| return m_params; | ||
| } |
There was a problem hiding this comment.
if the creation params are identical for Gfx and MEsh, should go in ICPURasterizationPipeline
| namespace nbl::asset | ||
| { | ||
|
|
||
| class ICPUMeshPipeline final : public ICPUPipeline<IMeshPipeline<ICPUPipelineLayout,ICPURenderpass>> |
There was a problem hiding this comment.
make a ICPURasterizationPipeline : IRasterizationPipeline<ICPUPipelineLayout,ICPUrenderpass>
| namespace nbl::video | ||
| { | ||
|
|
||
| class IGPUMeshPipeline : public IGPUPipeline<asset::IMeshPipeline<const IGPUPipelineLayout, const IGPURenderpass>> | ||
| { |
There was a problem hiding this comment.
no extra indents for a namespace
| bool MeshGraphicsCommonValidation( | ||
| const IGPURenderpass* renderpass, uint8_t subpassIndex, | ||
| SPhysicalDeviceLimits const& limits, SPhysicalDeviceFeatures const& features, | ||
| nbl::asset::SRasterizationParams const& rasterParams, nbl::asset::SBlendParams const& blendParams, | ||
| const system::logger_opt_ptr m_logger, | ||
| const IPhysicalDevice::SFormatImageUsages& formatUsages | ||
| ) { |
There was a problem hiding this comment.
make it a method of ILogicalDevice so you don't have to pass features, limits, logger and format usages around
| if (!features.taskShader) { | ||
| NBL_LOG_ERROR("Feature `mesh shader` is not enabled"); |
| return false; | ||
| } | ||
|
|
||
| if (ci.geometryShader.shader) |
There was a problem hiding this comment.
yes you've found a typo, well done!
| //check extensions here | ||
| //it SEEMS like createGraphicsPipeline does, but it does it in a weird way I don't understand? | ||
| //geo and tess are just flat disabled?? |
There was a problem hiding this comment.
its because we never used them, typo galore, you can fix
| if (ci.tesselationEvaluationShader.shader) | ||
| { | ||
| NBL_LOG_ERROR("Cannot create IGPUShader for %p, Tessellation Shader feature not enabled!", ci.tesselationEvaluationShader.shader); | ||
| return false; | ||
| } | ||
|
|
||
| if (ci.geometryShader.shader) | ||
| { | ||
| NBL_LOG_ERROR("Cannot create IGPUShader for %p, Geometry Shader feature not enabled!", ci.geometryShader.shader); | ||
| return false; | ||
| } |
| auto renderpass = ci.renderpass; | ||
| if (!renderpass->wasCreatedBy(this)) | ||
| { | ||
| NBL_LOG_ERROR("Invalid renderpass was given (params[%u])", ix); | ||
| return false; | ||
| } |
There was a problem hiding this comment.
this can be commonalized in MeshGraphicsCommonValidation I think
| https://registry.khronos.org/vulkan/specs/latest/man/html/VkGraphicsPipelineCreateInfo.html#VUID-VkGraphicsPipelineCreateInfo-PrimitiveId-06264 | ||
| ** If the pipeline requires pre-rasterization shader state, it includes a mesh shader and the fragment shader code reads from an input variable that is decorated with PrimitiveId, then the mesh shader code must write to a matching output variable, decorated with PrimitiveId, in all execution paths |
There was a problem hiding this comment.
this you can't validate cheaply without parsing SPIR-V, also its an "all execution paths" thing so its a runtime thing to be checked with GPU AV layer
| https://registry.khronos.org/vulkan/specs/latest/man/html/VkGraphicsPipelineCreateInfo.html#VUID-VkGraphicsPipelineCreateInfo-renderPass-07064 | ||
| * If renderPass is not VK_NULL_HANDLE, the pipeline is being created with pre-rasterization shader state, subpass viewMask is not 0, and multiviewMeshShader is not enabled, then pStages must not include a mesh shader |
There was a problem hiding this comment.
you can check that
| https://registry.khronos.org/vulkan/specs/latest/man/html/VkGraphicsPipelineCreateInfo.html#VUID-VkGraphicsPipelineCreateInfo-None-02322 | ||
| * If the pipeline requires pre-rasterization shader state, and there are any mesh shader stages in the pipeline there must not be any shader stage in the pipeline with a Xfb execution mode | ||
| *** whats a xfb | ||
|
|
There was a problem hiding this comment.
transform feedback, a nasty OpenGL carryover extension we don't use
| https://registry.khronos.org/vulkan/specs/latest/man/html/VkGraphicsPipelineCreateInfo.html#VUID-VkGraphicsPipelineCreateInfo-shaderMeshEnqueue-10187 | ||
| * If the shaderMeshEnqueue feature is not enabled, shaders specified by pStages must not declare the ShaderEnqueueAMDX capability | ||
| https://registry.khronos.org/vulkan/specs/latest/man/html/VkGraphicsPipelineCreateInfo.html#VUID-VkGraphicsPipelineCreateInfo-flags-10188 | ||
| * If flags does not include VK_PIPELINE_CREATE_LIBRARY_BIT_KHR, shaders specified by pStages must not declare the ShaderEnqueueAMDX capability | ||
| *** my understanding is nabla strictly controls it's extensions, so this shouldnt be an issue |
There was a problem hiding this comment.
year we're not going into AMDX or NVX extensions, also no pipeline libs yet
| https://registry.khronos.org/vulkan/specs/latest/man/html/VkGraphicsPipelineCreateInfo.html#VUID-VkGraphicsPipelineCreateInfo-pDynamicStates-07066 | ||
| * If the pipeline requires pre-rasterization shader state, and includes a mesh shader, there must be no element of the | ||
| * pDynamicStates member of pDynamicState set to VK_DYNAMIC_STATE_PRIMITIVE_RESTART_ENABLE, or VK_DYNAMIC_STATE_PATCH_CONTROL_POINTS_EXT | ||
|
|
There was a problem hiding this comment.
we choose the dynamic state ourselves (opinionated pick), and I think we never made those two dynamic, ever
maybe check the PRIMITIVE_RESTART enable
| https://registry.khronos.org/vulkan/specs/latest/man/html/VkGraphicsPipelineCreateInfo.html#VUID-VkGraphicsPipelineCreateInfo-renderPass-07720 | ||
| * If renderPass is VK_NULL_HANDLE, the pipeline is being created with pre-rasterization shader state, and | ||
| * VkPipelineRenderingCreateInfo::viewMask is not 0, and multiviewMeshShader is not enabled, then pStages must not include a mesh shader | ||
|
|
There was a problem hiding this comment.
what its saying is that you can't use multivew in pipeline create info with a mesh shader if you don't have the multiviewMeshShader feature
Basically there's the old multivew feature, but that only controls if multiview is available for a graphics pipeline, for mesh you have another thing to check instead
| namespace nbl::video | ||
| { | ||
|
|
||
| class IGPUMeshPipeline : public IGPUPipeline<asset::IMeshPipeline<const IGPUPipelineLayout, const IGPURenderpass>> |
There was a problem hiding this comment.
it seems you have not commited the file with IMeshPipeline !
| static inline int8_t stageToIndex(const hlsl::ShaderStage stage) | ||
| { | ||
| const auto stageIx = hlsl::findLSB(stage); | ||
| if (stageIx < 0 || stageIx >= MESH_SHADER_STAGE_COUNT || hlsl::bitCount(stage)!=1) | ||
| return -1; | ||
| return stageIx; | ||
| } |
There was a problem hiding this comment.
I'm fairly certain this is wrong, and you need to return stageIx-offset since only in gfx pipeline VERTEX is 0th bit
| if (!processSpecInfo(fragmentShader, hlsl::ShaderStage::ESS_FRAGMENT)) return {}; | ||
|
|
||
| if (!hasRequiredStages(stagePresence)) | ||
| return {}; |
There was a problem hiding this comment.
because you haven't committed the IMeshPipeline.h file I can't see the impl of this
| if (!hasRequiredStages(stagePresence)) | ||
| return {}; | ||
|
|
||
| //if (!vertexShader.shader) return {}; //i dont quite understand why this line was in IGPUGraphics. checking if the shader itself was made correctly? |
There was a problem hiding this comment.
its because graphics pipeline MUST have a vertex shader, much like how a Mesh pipeline must have a mesh shader
Fragment and Task are optional for mesh pipe
|
|
||
| inline uint32_t getShaderCount() const | ||
| { | ||
| uint32_t count = 0; //count = 2 and only check task shader?? |
There was a problem hiding this comment.
no what you have now is correct
Mesh Pipelines
Description of changes that aren't implicit.
Testing
https://github.com/GDBobby/Nabla-Examples-and-Tests/tree/master/MeshShader